package com.yukefms.rule.state;

import com.yukefms.engine.running.EventCode;
import com.yukefms.engine.running.RunningContext;
import com.yukefms.engine.running.RunningEvent;
import com.yukefms.jointpoint.BodyPointCloud;
import com.yukefms.rule.interfaces.BARule;
import com.yukefms.rule.interfaces.BAStageRule;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * @Description
 * @Author Ping
 * @Date 2021/6/29 10:25
 **/
public class ActivatedState extends BARuleState {
    public static Logger logger = LogManager.getLogger(ActivatedState.class);

    public ActivatedState(final BAStageRule relatedRule) {
        super(relatedRule);
    }

    @Override
    protected void processRelevantPointsCloud(BodyPointCloud pointCloud, RunningContext context) {

//        context.notifyRunningEventListener(EventCode.ACTIVED, this.relatedRule.ruleName());
//        logger.error("the Rule-{} was Activated.", this.relatedRule.ruleName());
        // check if the dynamic action is performing
        if (this.relatedRule.isPerforming(pointCloud, context)) {
            // check if the performing is well.
            if (this.relatedRule.invariantSatisfied(pointCloud, context)) {
                // check if the reponse is arrived.
                if (this.relatedRule.responseArrived(pointCloud, context)) {
                    /**
                     * if there is not more response needed to finished, then transition to success state,
                     * otherwise transition to next response and dynamic.
                     * transtion to success state.
                     */
                    logger.error("the Rule-{} was FINISHED stage {} for current point cloud.",
                            this.relatedRule.ruleName(), this.relatedRule.currentStage().getName());
                    if (! this.relatedRule.hasNextStage()) {
                      /*  context.updateScore(relatedRule.successScore());
                        context.notifyRunningEventListener(EventCode.SUCCESS, this.relatedRule.ruleName());*/
                        logger.error("the Rule-{} was SUCCESS for current point cloud.",
                                this.relatedRule.ruleName());
                        this.relatedRule.setRuleState(RuleStateFlyWeight.getState(RuleStateFlyWeight.SUCCESS));
                        this.relatedRule.doReaction(pointCloud, context);
                        return;
                    } else {
                        /**
                         * to the next stage with new dyanmic and response.
                         */
                        context.updateScore(relatedRule.currentStage().getScore());
                        context.notifyRunningEventListener(EventCode.ACTIVED, this.relatedRule.currentStage().getName());
                        this.relatedRule.toNextStage();
                        logger.error("Next stage for the Rule-{}:  {}.", this.relatedRule.ruleName()
                                , this.relatedRule.currentStage().getName()) ;
                    }

                } else {
                    /**
                     * did not arrive response action but still performing well
                     */
                    context.notifyRunningEventListener(EventCode.ACTIVED, relatedRule.currentStage().getName());
//                    logger.error("the Rule-{} is performing well for current point cloud.", this.relatedRule.ruleName());
                }
            } else {
                // if performing not well, i.e., the invariant does not satified, then transition to the wrong performing state
                //here, should considering invariant failed tolerant.
                context.updateInvariantFailCounter();
                context.notifyRunningEventListener(EventCode.ACTIVED,
                                                     relatedRule.currentStage().getName(),
                                                     relatedRule.getInvariant().getDescription());
                //if not invarint.
                if (context.getInvariantFailCounter().isOverMax()) {
                    logger.error("The invariant formula of RULE-{} is NOT SATISFIED since InvariantFail overtime and transitioned to WRONG PERFORMING."
                            , this.relatedRule.getInvariant().getName());
                    context.updateScore(relatedRule.currentStage().getScore()) ;
                    context.notifyRunningEventListener(EventCode.PARTIAL_MATCHED, relatedRule.currentStage().getName());
                    context.getInvariantFailCounter().reset();
                    this.relatedRule.setRuleState(RuleStateFlyWeight.getState(RuleStateFlyWeight.WRONG_PERFORMING));
                }

            }
        } else {
            // tolereant for not performing
            context.updatePerformingFailCounter();
            // if not dynamic
            if (context.getPerformingFailCounter().isOverMax()) {
                logger.error("The performing formula of RULE-{} is NOT SATISFIED since perform fail overtime and transitioned to unmatched"
                        , this.relatedRule.currentStage().getName());
                context.notifyRunningEventListener(EventCode.UNMATCHED, relatedRule.currentStage().getName()) ;

                context.getPerformingFailCounter().reset();
                context.getInvariantFailCounter().reset();
                this.relatedRule.setRuleState(RuleStateFlyWeight.getState(RuleStateFlyWeight.UN_MATCHED));
                this.relatedRule.doReaction(pointCloud, context);
                // finished current trial and not necessary to caching current pointcloud .
                return ;
            }
        }
        // cache current point cloud and for the next
        context.updateCachingPointCloud(pointCloud);

    }

    @Override
    public double getScore() {
        return this.relatedRule.getTrigger().getScore();
    }
}
